#ifndef _OPENGLAPPFRAMEWORK_GAMEOBJECT_H_
#define _OPENGLAPPFRAMEWORK_GAMEOBJECT_H_

#include "OpenglAppFramework/inc/OpenglEnv.h"
#include "OpenglAppFramework/inc/TextureManager.h"
#include "OpenglAppFramework/inc/glm/glm.hpp"
#include "json/inc/json.hpp"
#include <string>
#include <vector>
#include <map>

class TransformInfo {
public:
    glm::vec3 location;  // 相对于父物体或世界原点的位移，即位置坐标
    glm::vec3 scale;
    glm::vec3 rotation_axis; // 旋转轴
    float rotation_angle;   // 旋转角度（degree）

    static void ToModelMat(const TransformInfo& ts_info, glm::mat4& model_mat);
};

class PlugIn;
class Camera;
class Material;
class Mesh;
class LightSource;
class ActionsPlugIn;
class InstancingPlugIn;
class LODPlugIn;
class Shader;

using PlugIns = std::map<std::string, PlugIn*>;

class Scene;
class GameObject {
private:
    GameObject();
public:
    ~GameObject();
    static GameObject* CreateGameObjectByJson(Scene* manager, const std::string& name, const nlohmann::json& js);
    void set(Scene* manager, const std::string& name, const TransformInfo& trans, bool is_static, bool is_cast_shadow);

    int initAllPlugIns();
    void setPlugIn(PlugIn* plugins);
    void changePlugIn(PlugIn* plugins); // 与setPlugIn的区别是，不修改m_plugins
    void setPlugIns(const std::vector<PlugIn*>& plugins);
    void setMesh(PlugIn* plugin);
    void setMaterial(PlugIn* plugin);
    void setCamera(PlugIn* plugin);
    void setLightSource(PlugIn* plugin);
    void setLocation(const glm::vec3& loc);
    void setRotation(const glm::vec3& aixs, float degree);
    void setScale(const glm::vec3& scale);
    void updateModelMat();
    void uploadModelMat(Shader* s);

    const std::string& name() const;
    const TransformInfo& transformInfo() const;
    const glm::mat4& modelMat() const;
    bool isStatic() const;
    bool isInstancing() const;
    bool isCastShadow() const;
    Mesh* getMesh();
    Material* getMaterial();
    LightSource* getLightSource();
    Camera* getCamera();
    InstancingPlugIn* getInstancingPlugIn();
    PlugIns& plugIns();
    // 找不到返回nullptr
    PlugIn* getPlugInByName(const std::string& name); 

    Scene* scene();
    TextureManager& textureManger();

    void render();
    
private:
    std::string m_name;
    TransformInfo m_transform;
    bool m_is_transform_changed;
    glm::mat4 m_model_mat;
    bool m_is_static;
    bool m_is_cast_shadow;

    PlugIns m_plugins;
    Camera* m_camera;
    LightSource* m_light_source;
    Mesh* m_mesh;
    Material* m_material;
    InstancingPlugIn* m_instancing_plugin;
    ActionsPlugIn* m_action;
    LODPlugIn* m_lod;

    TextureManager m_texutre_manager;
    Scene* m_scene;

    // std::vector<GameObject*> m_children;
    // GameObject* m_root;
    // GameObject* m_parent;
};

#endif//_OPENGLAPPFRAMEWORK_GAMEOBJECT_H_
